Skip to content

feat(routes): type callers by schema input; per-program AB4834; validate before typecheck (#748, #752) - #757

Merged
ScriptedAlchemy merged 9 commits into
mainfrom
feat/748-752-route-types
Sep 8, 2026
Merged

feat(routes): type callers by schema input; per-program AB4834; validate before typecheck (#748, #752)#757
ScriptedAlchemy merged 9 commits into
mainfrom
feat/748-752-route-types

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Closes #748. Closes #752.

What

#752 — caller input vs parsed handler output. The generated .agent-bundle/routes.d.ts now derives each route's input from the schema's _input (what a caller sends) instead of _output. createAppClient().call, onToolInput, renderRoute, invokeMcpTool, and contract-matrix fixtures accept {} for z.object({ limit: z.number().default(10) }) and a string for a .transform()ed field; ToolRouteProps<typeof inputSchema>['input'] keeps the parsed output. A structural schema declaring only _output uses it for both (explicit rule, spelled in the generated file). renderRoute now parses input through the route's own inputSchema at the same boundary the generated Flight worker does — defaults filled, transforms applied once — and rejects invalid input with invalid-input before any provider or component runs. LoadedRouteModule.inputSchema.parse returns unknown (the parsed props are not part of the registration).

#748 — reliable typegen / per-program AB4834. routeTypesProgramDiagnostics walks references transitively and reports AB4834 once per program that consumes the registration (a source file importing agent-bundle/app, agent-bundle/test, agent-bundle/eval, or @agent-bundle/runtime) and omits the declaration; build-only projects are left alone; recovery names the include path relative to the offending tsconfig. The documented entry for current declarations before an isolated typecheck is agent-bundle validate (~3s, no bundle): the mcp-server and cli-tool starters' typecheck is now npm run validate && tsc, and check no longer runs validate twice.

Tests

  • tests/route-caller-input-types.test.ts (integration): clean generated project with a solution-style root (tsconfig.app.json browser program with lib: DOM, tsconfig.node.json server program). validate publishes the declaration; both real tsconfig programs type-check via ts.parseJsonConfigFileContent; client.call('tool:curator/page', {}), onToolInput with optional default, transform input as string; negatives (wrong id, missing required, wrong primitive, parsed-number-as-caller) each one error; dropping the declaration from the browser program alone yields one AB4834 on that program; built MCP server round trip applies default/transform once and rejects invalid input before the handler runs (invocation log).
  • tests/route-types-program.test.ts: nested references, excluded declaration, build-only project untouched, recovery path relative to nested tsconfig.
  • tests/route-graph.test.ts: _input-bearing and _output-only structural stand-ins.
  • tests/route-unit/render-route.test.ts: renderRoute applies the default and rejects { label: 1 } with invalid-input.
  • route-register-typegen, generated-route-server, route-contract-imports updated/green; packed scaffold matrix (mcp-server, cli-tool, minimal) green with the new typecheck script.

Docs

en+zh: guide/development/testing.mdx, guide/development/index.mdx, guide/authoring/mcp.mdx; docs/diagnostics.md (AB4834); docs/entry-conventions.md; starter READMEs. No overlap with #754's paths.

Gate (current origin/main)

pnpm build && pnpm typecheck && pnpm lint ✅ · pnpm test:unit ✅ · route-unit pool (90) ✅ · projection pool (191) ✅ · test:packed:release scaffold matrix ✅ · full integration pool + pnpm docs:site:build: running, results appended below.

Deslop: pending. Self-review: pending.

@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f046cf8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
agent-bundle Minor
@agent-bundle/runtime Minor
create-agent-bundle Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 7, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@757
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@757
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@757
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@757

commit: f046cf8

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2f9fd454b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"create-agent-bundle": patch
---

Type route callers by schema input and route components by schema output in the generated `.agent-bundle/routes.d.ts`: `createAppClient().call`, `onToolInput`, `renderRoute`, `invokeMcpTool`, and the contract matrix accept what a caller sends (a `.default()`ed field is optional, a `.transform()`ed field is spelled as the wire carries it), while `ToolRouteProps` keeps the parsed output. A structural schema declaring only `_output` uses it for both. `renderRoute` now parses its input through the route's own `inputSchema` before the component runs and fails with an `invalid-input` harness error on rejected input. `agent-bundle validate` reports `AB4834` once per TypeScript program that imports `agent-bundle/app`, `agent-bundle/test`, `agent-bundle/eval`, or `@agent-bundle/runtime` and omits the generated declaration — following `references` transitively — instead of accepting any one referenced program that includes it. The `mcp-server` and `cli-tool` starters run `agent-bundle validate` inside `npm run typecheck`, so a clean checkout type-checks against current route declarations. (#PR)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Replace the placeholder PR reference

The changeset leaves (#PR) as a literal placeholder, so it will be published in the user-facing release notes instead of identifying this change; replace it with the actual PR reference (the commit identifies #748/#752). Repository guidance requires changeset summaries to include the PR number and prohibits implementation-note placeholders.

AGENTS.md reference: AGENTS.md:L167-L168

Useful? React with 👍 / 👎.


/** Whether one of the program's own source files imports a module the generated declaration augments. */
const consumesRegistration = (fileNames: readonly string[]): boolean =>
fileNames.some((fileName) => !fileName.endsWith('.d.ts') && consumerImport.test(ts.sys.readFile(fileName) ?? ''));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Inspect transitive source files for AB4834

When a config uses files: ["src/index.ts"] or an equivalently narrow include, and that entry point imports another local module which imports agent-bundle/test, agent-bundle/app, or the runtime, parseJsonConfigFileContent().fileNames contains only the configured root files even though tsc follows the imported module into the program. Scanning only this array therefore reports no AB4834 while the actual program consumes the registration without .agent-bundle/routes.d.ts, leaving route IDs and values loosely typed; consumer detection needs to inspect the semantic program or traverse its imports.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T23:43:54.161283Z b2f9fd4 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Codex first-pass findings, addressed locally:

  1. Changeset (#PR) placeholder — fixed in dbb8408; the summary now ends with (#757).
  2. AB4834 scanned only the configured root files — correct: parseJsonConfigFileContent().fileNames is the root list, so files: ["src/index.ts"] importing a consumer was missed. typegen-program.ts now builds the program from those roots (ts.createProgram, host declining node_modules, noLib, types: []) and scans getSourceFiles(), i.e. the same import closure tsc -p compiles; a declaration reached through /// <reference> also counts as compiled. Regression test: route-types-program.test.ts “follows imports from a narrow root”. validate on examples/host-test costs ~0.6 s more.

Also fixed from the failed Examples check: examples/host-test rendered slow with tickMs: 40 against a schema whose minimum is 50 — a path the runtime rejects; now that renderRoute parses input, the test uses tickMs: 50 (17924a5). pnpm examples:check passes locally.

@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/748-752-route-types branch from 3546536 to f046cf8 Compare September 8, 2026 02:07
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Local gate at f046cf8 (rebased on current origin/main): pnpm build, pnpm typecheck, pnpm lint, pnpm test:unit, pnpm test:integration (whole pool, 1171 passed / 0 failed), pnpm examples:check (Examples root cause: examples/host-test slow probe sent tickMs: 40 below the tool's min(50); the harness now validates, the test was corrected rather than the check loosened), create-agent-bundle packed scaffold e2e, pnpm docs:site:build — all green. Independent local review (Fable): nothing blocks.

@ScriptedAlchemy
ScriptedAlchemy merged commit 8acc0ed into main Sep 8, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant